#include "Shell.h"
#include <fstream>
#include <stdlib.h>
using namespace std;

Shell::Shell()
{
	//start();
	mainRun();
}

Shell::~Shell()
{
}

void Shell::mainRun()
{
	bool alive = true;
	string arg = "";
	int choice;
	while (alive)
	{
		cout<<"==============================="<<endl;
		cout<<"please select on of the options below"<<endl;
		cout<<"1. create net"<<endl;
		cout<<"2. KillNode"<<endl;
		cout<<"3. ReviveNode"<<endl;
		cout<<"4. Killall"<<endl;
		cout<<"5. PrintRT"<<endl;
		cout<<"6. SendPacket"<<endl;
		cout<<"7. Run"<<endl;
		cout<<"8. Exit"<<endl;

		cin >> choice;

		switch (choice) {

		case 1: //createNet
			//cout << "enter file name" <<endl;
			//cin >> arg;
			arg = "data.txt";
			CreateNet(arg);
			break;

		case 2: //KillNode
			KillNode();
			break;

		case 3: //ReviveNode
			ReviveNode();
			break;

		case 4: //Killall
			Killall();
			break;

		case 5: //PrintRT
			PrintRT();
			break;

		case 6: //SendPackket
			SendPacket();
			break;

		case 7: //Run
			Run();
			cout<<"SHELL:: case 7 "<<endl;
			break;

		case 8: //Exit
	//		alive = false;
			cout << " Bye Bye... " <<endl;
			alive = false;
//			_mailer
			break;

		default:
			cout<< "please select a number between 1 and 9"<<endl;
			break;
		}
	}
}
/* creates Mailer
 * creates Nodes
 * creates  RTs
 *
 * #1 = Mailer buffer size
 * #2 = # of nodes in system
 * #3 = ID Neighbor1,Neighbor2,...
 * */
void Shell::CreateNet(string arg)
{
	ifstream argFile;
	argFile.open(arg.c_str());
	vector<int> vline;

	if (argFile.is_open())
	{
		string line;
		cout << arg<<" is open"<<endl;
		// get first argument
		getline(argFile,line);
		int buffSize = atoi(line.c_str());

		// get 2nd argument
		getline(argFile,line);
		int numOfNodes = atoi(line.c_str());

		//creating the Mailer
		_mailer = new Mailer(buffSize,numOfNodes);

		//gets nodes and neighbors and sends to mailer
		// creates Nodes
		for (int i = 0; i < numOfNodes; ++i) {
			getline(argFile,line);
			vline = intTokenizer(line); // holds  vector of all ids
			_mailer->createNode(vline);
		}

		//creating RTs
		_mailer->createRTs();

		argFile.close();
	}
	else
		cout << arg<<" could not open"<<endl;
}

vector<int> Shell::intTokenizer(string s){
	vector<int> ans;
	string tmp="";
	int lastIndex=0;
	for (int i = 0; i < s.length(); ++i) {
		if (s.substr(i,1).compare(" ")==0 ){   //i == " "
			tmp = s.substr(lastIndex,i-lastIndex);
			lastIndex = i+1;
			ans.push_back(atoi(tmp.c_str()));
		}

	}
	//dealing with last part of string
	tmp = s.substr(lastIndex,s.length()-lastIndex);
	ans.push_back(atoi(tmp.c_str()));
	return ans;
}

void Shell::Run()
{
	//cout<<"shell:running algorithm num: "<< num << endl;
	_mailer->start();
	sleep(5);
	pthread_cond_t var = _mailer->getShellCondVar();
	pthread_mutex_t mutex = _mailer->getShellMutex();
//	pthread_mutex_lock(&mutex);
//	pthread_cond_wait(&var, &mutex);
//	pthread_mutex_unlock(&mutex);

	cout<<"SHELL::Run:  mutex unlock -"<<endl;
}

void Shell::KillNode()
{
	int num;
	cout<<"Please enter the id of node you like to kill"<<endl;
	cin>>num;
	System_Message* sys = new System_Message("killNode", num);
	Message* msg = new Message(0,0,sys);
	sendMsgToMailer(msg);
}

void Shell::ReviveNode()
{
	int num;
	cout<<"Please enter the id of node you like to revive"<<endl;
	cin>>num;
	System_Message* sys = new System_Message("reviveNode", num);
	Message* msg = new Message(0,0,sys);
	sendMsgToMailer(msg);
}

void Shell::Killall()
{
	System_Message* sys = new System_Message("killAll");
	Message* msg = new Message(0,0,sys);
	sendMsgToMailer(msg);
}

void Shell::PrintRT()
{
	int num;
	cout<<"Please enter the id of which node's rt you would like to pirnt."<<endl;
	cin>>num;
	System_Message* sys = new System_Message("printRt", num);
	Message* msg = new Message(0,0,sys);
	sendMsgToMailer(msg);
}

void Shell::SendPacket()
{
	int src;
	int target;
	string txt;
	cout<<"enter source"<<endl;
	cin>>src;
	cout<<"enter target"<<endl;
	cin>>target;
	cout<<"enter text to send"<<endl;
	cin>>target;
	System_Message* sys = new System_Message("sendPacket",src,target, txt);
	Message* msg = new Message(0,0,sys);
	sendMsgToMailer(msg);
}

void Shell::sendMsgToMailer(Message* msg)
{
	pthread_mutex_t mutex = _mailer->getMailboxMutex();
	pthread_cond_t cond = _mailer->getMailboxCondVar();

	//catch Mutex
	pthread_mutex_lock(&mutex);

	while(_mailer->fullInbox())
	{
		//wait on condition variable:
		pthread_cond_wait(&cond, &mutex);
	}
	//ADD TO MAILBOX
	_mailer->addFirst(msg);
	pthread_mutex_unlock(&mutex);
}
